/**
 * @brief COMM V1 is a common message-based communication framework between modules
 * COMM V1 messages are in the following structure:
 -------------------------------------------------------------------------------------
 | symbol |  SOF  | Snd | Rcv | SN | ID | LEN | CS0 | D[1] | D[2] | ... | D[N] | CS1 |
 -------------------------------------------------------------------------------------
 |  size  |   1   |  1  |  1  | 1  | 2  |  2  |  1  |  1   |  1   | ... |  1   |  2  |
 -------------------------------------------------------------------------------------
 */
#ifndef __COMM_V1_H__
#define __COMM_V1_H__


#include <stdint.h>
#include "comm.h"
#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief definition of the comm v1 handle
 */
typedef void *comm_v1_handle_t;

#pragma pack(push, 1)

/**
 * @brief definition of the message structure
 */
typedef struct {
    uint8_t  start;      /**< start of message >*/
    uint8_t  sender;     /**< sender >*/
    uint8_t  receiver;   /**< receiver >*/
    uint8_t  seq_num;    /**< sequence number >*/
    uint16_t message_id; /**< message id >*/
    uint16_t length;     /**< message length >*/
    uint8_t  checksum0;  /**< checksum for the head >*/
} comm_v1_header_t;

#pragma pack(pop)

/**
 * @brief definition of parse error
 */
typedef enum {
    PARSE_ERROR_TYPE_SOF = 0,   /* sof not match */
    PARSE_ERROR_TYPE_CHECKSUM0, /* header checksum not match */
    PARSE_ERROR_TYPE_LENGTH,    /* message exceeds max size */
    PARSE_ERROR_TYPE_CHECKSUM1, /* body checksum not match */
    PARSE_ERROR_TYPE_UNDEFINED  /* undefined error */
} parse_error_type_t;

/**
 * @brief definition of the comm v1 runtime
 */
typedef struct {
    const char *name;
    uint8_t id;
    uint8_t line;
    comm_v1_handle_t handle;
} comm_v1_runtime_t;

/**
 * @brief definition of the message handler
 * @para [in] runtime: runtime info of the comm v1 instance
 * @para [in] header: message header with more information about this message
 * @para [in] message: payload bytes of this message
 * @para [in] length: message length
 * @return none
 */
typedef void (* comm_v1_message_handler_t)(const comm_v1_runtime_t *runtime,
                                           const comm_v1_header_t *header,
                                           const uint8_t *message, uint32_t length);

/**
 * @brief definition of the transmit handler
 * @para [in] runtime: runtime info of the comm v1 instance
 * @para [in] data: data to send
 * @para [in] length: length of the data
 * @return number of bytes sent
 */
typedef uint32_t (* comm_v1_transmit_handler_t)(const comm_v1_runtime_t *runtime, const uint8_t *data, uint32_t length);

/**
 * @brief definition of parse error handler
 * @para [in] runtime: runtime info of the comm v1 instance
 * @para [in] error_type: error type that has occurred
 */
typedef void (* parse_error_handler_t)(const comm_v1_runtime_t *runtime,
                                       parse_error_type_t error_type);

/**
 * @brief comm v1 configuration
 */
typedef struct {
    const char *name;                            /* name of this comm v1 instance */
    uint8_t id;                                  /* self id */
    uint8_t line;
    uint8_t start_of_frame;                      /* start of frame */
    uint32_t max_message_length;                 /* max message length */
    comm_v1_message_handler_t message_handler;   /* message handler */
    comm_v1_transmit_handler_t transmit_handler; /* transmit handler to send messages out */
    parse_error_handler_t parse_error_handler;   /* parse error handler */
} comm_v1_config_t;

/**
 * @brief create an instance of the comm v1 module
 * @para [in] comm v1 configuration
 * @return a valid #comm_v1_instance_t on success, null ptr otherwise
*/
comm_v1_handle_t comm_v1_create(const comm_v1_config_t *config);

/**
 * @brief compose v1 message with payload
 * @para [in] handle: comm v1 instance created by #comm_v1_create
 * @para [in] sender: sender id
 * @para [in] receiver: receiver id
 * @para [in] seq_num: sequence number
 * @para [in] message_id: message id
 * @para [in] payload: user defined message content
 * @para [in] length: length of the payload
 * @return SUCC on success, FAiL otherwise
*/
int32_t comm_v1_send_message(comm_v1_handle_t handle, uint8_t sender, uint8_t receiver,
                             uint8_t seq_num, uint16_t message_id, const uint8_t *payload, uint32_t length);

/**
 * @brief parse messages from the given data
 * @para [in] handle: comm v1 instance created by #comm_v1_create
 * @para [in] data: incoming data to be processed
 * @para [in] length: length of data
 * @return SUCC on success, FAiL otherwise
*/
int32_t comm_v1_process(comm_v1_handle_t handle, const uint8_t *data, uint32_t length);
/**
 * @brief parse messages from the given data
 * @para [in] handle: comm v1 instance created by #comm_v1_create
 * @para [in] data: incoming data to be processed
 * @para [in] data_len: length of data
 * @para [in] parse_msg: output data is needed
 * @para [in] parse_len: length of parse_msg
 * @return SUCC on success, FAiL otherwise
*/
int32_t comm_v1_once_parse(comm_v1_handle_t handle, const uint8_t *data, uint16_t data_len,comm_v1_header_t *header,uint8_t *parse_msg,uint16_t parse_max_len);
// int32_t comm_v1_once_parse(comm_v1_handle_t handle, const uint8_t *data, uint16_t data_len,comm_v1_header_t *header,uint8_t *parse_msg,uint16_t parse_len);

/**
 * @brief destroy a comm v1 module
 * @para [in] handle: comm v1 instance created by #comm_v1_create
 * @return SUCC on success, FAIL otherwise
*/
int32_t comm_v1_destroy(comm_v1_handle_t handle);

void comm_v1_reset(comm_v1_handle_t handle);

#ifdef __cplusplus
}
#endif

#endif // __COMM_V1_H__
